/*
 * This file is part of the <a href="http://code.google.com/p/pux">PUX Framework</a>
 *
 * Copyright 2008 by <a href="mailto:jfendler@polytechnic.edu.na">Jens Fendler</a>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package de.teamskill.pux.library.xml;

import java.util.List;

import org.jdom.Document;
import org.jdom.JDOMException;
import org.jdom.xpath.XPath;

import de.teamskill.pux.engine.InputPort;
import de.teamskill.pux.engine.AbstractNode;
import de.teamskill.pux.engine.OutputPort;

/**
 * XPathNode
 * 
 * @author <a href="mailto:jfendler@polytechnic.edu.na">Jens Fendler</a>
 * 
 */
public class XPathNode extends AbstractNode {

	/**
	 * IN_DOCUMENT
	 */
	public static final String IN_DOCUMENT = "DOCUMENT";

	/**
	 * OUT_LIST
	 */
	public static final String OUT_LIST = "LIST";

	/**
	 * CONFIG_XPATH
	 */
	public static final String CONFIG_XPATH = "xPath";

	/**
	 * in
	 */
	private InputPort in;

	/**
	 * path
	 */
	private InputPort path;

	/**
	 * listOut
	 */
	private OutputPort listOut;

	/**
	 * XPathNode Constructor
	 * 
	 */
	public XPathNode() {
		this("XPATH" + nr++, false);
	}

	/**
	 * XPathNode Constructor
	 * 
	 * @param nodeName
	 * @param continuous
	 */
	public XPathNode(String nodeName, boolean continuous) {
		super(nodeName, continuous);
	}

	/**
	 * @see de.teamskill.pux.engine.AbstractNode#compute()
	 */
	@SuppressWarnings("unchecked")
	public void compute() {
		String xPathExp = (String) path.fetchData();
		XPath xPath = null;
		try {
			xPath = XPath.newInstance(xPathExp);
		} catch (JDOMException e) {
			LOG_NODE.severe(getNodeName() + ": failed to parse XPath expression '" + xPathExp + "': "
					+ e.getLocalizedMessage());
		}
		try {
			Document doc = (Document) in.fetchData();
			// System.out.println("Document is " + doc); System.out.flush();
			while (doc == null) {
				try {
					Thread.sleep(50);
				} catch (InterruptedException e) {
					LOG_NODE.warning(getNodeName()
							+ ": Ignoring thread interruption while waiting for Document object: "
							+ e.getLocalizedMessage());
				}
				doc = (Document) in.fetchData();
			}
			List<Object> nodes = xPath.selectNodes(doc);
			listOut.pushData(nodes);
		} catch (JDOMException e) {
			LOG_NODE.severe(getNodeName() + ": failed to evaluate result for XPath expression '" + xPathExp
					+ "': " + e.getLocalizedMessage());
		}
	}

	/**
	 * @see de.teamskill.pux.engine.AbstractNode#createPorts()
	 */
	protected void createPorts() {
		in = addInputPort(IN_DOCUMENT, Document.class, true);
		path = addConfigurationPort(CONFIG_XPATH, String.class, "//*");
		listOut = addOutputPort(new OutputPort(OUT_LIST, this, List.class));
	}

	/**
	 * JavaBean-style getter-method for in
	 * 
	 * @return the in
	 */
	public InputPort getIn() {
		return in;
	}

	/**
	 * /** JavaBean-style setter-method for in
	 * 
	 * @param in
	 *            the in to set
	 */
	public void setIn(InputPort in) {
		this.in = in;
	}

	/**
	 * JavaBean-style getter-method for path
	 * 
	 * @return the path
	 */
	public InputPort getPath() {
		return path;
	}

	/**
	 * /** JavaBean-style setter-method for path
	 * 
	 * @param path
	 *            the path to set
	 */
	public void setPath(InputPort path) {
		this.path = path;
	}

	/**
	 * JavaBean-style getter-method for listOut
	 * 
	 * @return the listOut
	 */
	public OutputPort getListOut() {
		return listOut;
	}

	/**
	 * /** JavaBean-style setter-method for listOut
	 * 
	 * @param listOut
	 *            the listOut to set
	 */
	public void setListOut(OutputPort listOut) {
		this.listOut = listOut;
	}

}
